package com.pillpoppers.pillbox;

import java.util.ArrayList;
import java.util.Calendar;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.TimePickerDialog;
import android.app.TimePickerDialog.OnTimeSetListener;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.CheckedTextView;
import android.widget.ListView;
import android.widget.TimePicker;
import android.widget.Toast;

import com.pillpoppers.pillbox.database.Pill;
import com.pillpoppers.pillbox.database.PillboxDB;
import com.pillpoppers.pillbox.database.pillDB;

/**
 * 2 possible cases of reaching this activity:
 * 
 * 1. Creating a new Schedule from Schedule fragment
 *  = schedule id: No
 *  
 * 2. Editing an existing Schedule from Schedule fragment
 *  = schedule id: Attached
 */
public class AlarmSettingActivity extends Activity implements OnTimeSetListener, OnItemClickListener, OnClickListener {
	
	private final int NOT_EXIST = 0;
	
	private AlarmSettingAdapter adapter;
	private Schedule scheduleData;
	private boolean idCreated;
	private boolean idExists;
	private ArrayList<Pill> allPills;
	private ArrayList<Integer> pillSelectedIndex;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_alarm_setting);

		generateAllPillNames();
		initScheduleData(savedInstanceState);
		initViews();
	}
	
	private void initScheduleData(Bundle savedInstanceState) {
		if (savedInstanceState != null) {
			scheduleData = new Schedule(savedInstanceState);
			idCreated = savedInstanceState.getBoolean("idCreated");
			idExists = savedInstanceState.getBoolean("idExists");
			pillSelectedIndex = savedInstanceState.getIntegerArrayList("pillSelectedIndex");
		} else {
			int scheduleId = getIntent().getIntExtra("scheduleId", NOT_EXIST);
			
			if (scheduleId > NOT_EXIST) { // if id is passed, user is trying to modify this Schedule
				scheduleData = loadScheduleDataFromDb(scheduleId);
				idCreated = (scheduleData.getScheduleId() != NOT_EXIST);
				idExists = idCreated;
			} else { // case of making a new Schedule
				scheduleData = new Schedule(NOT_EXIST);
			}
			
			initPillSelectedIndex();
		}
		
	}
	
	private void generateAllPillNames() {
		pillDB db = new pillDB(this);
		allPills = db.getPills();
	}
	
	private void initPillSelectedIndex() {
		pillSelectedIndex = new ArrayList<Integer>();
		
		if (!scheduleData.getPillIds().isEmpty()) {
			getPillIndexById();
		}
		
	}
	
	private void getPillIndexById() {
		ArrayList<Integer> pillIds = scheduleData.getPillIds();
		for (int pillId : pillIds) {
			int index = findPillIndex(pillId);
			if (index != -1)
				pillSelectedIndex.add(index);
		}
	}
	
	private int findPillIndex(int pillId) {
		for (Pill pill : allPills) {
			if (pillId == pill.getPillID()) {
				return allPills.indexOf(pill);
			}
		}
		return -1;
	}
	
	private Schedule loadScheduleDataFromDb(int id) {
		PillboxDB db = new PillboxDB(this);
		Schedule schedule = db.getSchedule(id);
		if (schedule == null) {
			schedule = new Schedule(NOT_EXIST);
			idCreated = false;
		}
		return schedule;
	}
	
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putAll(scheduleData.getBundle());
		outState.putBoolean("idCreated", idCreated);
		outState.putBoolean("idExists", idExists);
		outState.putIntegerArrayList("pillSelectedIndex", pillSelectedIndex);
	}
	
	private void initViews() {
		ListView listView = (ListView) findViewById(R.id.alarm_setting_listview);

		adapter = new AlarmSettingAdapter(this, scheduleData);
		listView.setAdapter(adapter);
		listView.setOnItemClickListener(this);

		((Button) findViewById(R.id.cancel_btn)).setOnClickListener(this);
		Button deleteButton = (Button) findViewById(R.id.delete_btn);
		deleteButton.setOnClickListener(this);
		if (!idCreated)
			deleteButton.setEnabled(false);
		((Button) findViewById(R.id.save_btn)).setOnClickListener(this);
	}

	@Override
	public void onItemClick(AdapterView<?> parentView, View childView, int position, long id) {
		switch (position) {
		case Schedule.ACTIVE:
			updateCheckBoxStatus(childView);
			break;
		case Schedule.TIME:
			showTimePickerDialog();
			break;
		case Schedule.DAY_OF_WEEK:
			showDayOfWeekDialog();
			break;
		case Schedule.ALARM_BY:
			showAlarmByDialog();
			break;
		case Schedule.PILL_IDS:
			showPillSelectionDialog();
			break;
		}
	}
	
	private void updateCheckBoxStatus(View view) {
		CheckedTextView checkBox = (CheckedTextView) view.findViewById(android.R.id.text1);
		boolean checked = checkBox.isChecked();
		if (checked)
			checked = false;
		else
			checked = true;
		scheduleData.setActive(checked);
		adapter.notifyDataSetChanged();
	}
	
	private void showTimePickerDialog() {
		new TimePickerDialog(this, this, scheduleData.getHour(), scheduleData.getMinute(), false).show();
	}
	
	@Override
	public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
		scheduleData.setHour(hourOfDay);
		scheduleData.setMinute(minute);
		adapter.notifyDataSetChanged();
	}
	
	private void showDayOfWeekDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Day Of Week")
		.setSingleChoiceItems(AlarmSettingAdapter.DAY_OF_WEEK_OPTIONS, 
				scheduleData.getDayOfWeek() - 1, new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				scheduleData.setDayRepeat(which + 1);
			}
		})
		.setPositiveButton("OK", new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				adapter.notifyDataSetChanged();
			}
		})
		.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// dont do anything
			}
		})
		.create()
		.show();
	}
	
	private void showAlarmByDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Alarm By")
		.setItems(AlarmSettingAdapter.ALARM_BY_OPTIONS, new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				scheduleData.setAlarmBy(which);
				adapter.notifyDataSetChanged();
			}
		})
		.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// dont do anything
			}
		})
		.create()
		.show();
	}
	
	private void showPillSelectionDialog() {
		String[] allPillNames = new String[allPills.size()];
		for (int i = 0; i < allPillNames.length; i++)
			allPillNames[i] = allPills.get(i).getName();
		
		boolean[] checkedItems = new boolean[allPillNames.length];
		for (int index : pillSelectedIndex)
			checkedItems[index] = true;
		
		final ArrayList<Integer> selectedItems = new ArrayList<Integer>();
		for (int selectedIndex : pillSelectedIndex)
			selectedItems.add(selectedIndex);
		
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Pills")
		.setMultiChoiceItems(allPillNames, checkedItems, new OnMultiChoiceClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which, boolean isChecked) {
				
				if (isChecked) {
					if (!selectedItems.contains(which))
						selectedItems.add(which);
				} else if (selectedItems.contains(which))
					selectedItems.remove(Integer.valueOf(which));
			}
		})
		.setPositiveButton("OK", new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				refreshPillSelectedIndex(selectedItems);
				attachPillIds();
				adapter.notifyDataSetChanged();
			}
		})
		.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				// dont do anything
			}
		})
		.create()
		.show();
	}
	
	private void refreshPillSelectedIndex(ArrayList<Integer> selectedItems) {
		pillSelectedIndex.clear();
		for (int index : selectedItems)
			pillSelectedIndex.add(index);
	}
	
	private void attachPillIds() {
		ArrayList<Integer> pillIds = new ArrayList<Integer>(pillSelectedIndex.size()); // no need to be arraylist
		for (int i = 0; i < pillSelectedIndex.size(); i++)
			pillIds.add(allPills.get(pillSelectedIndex.get(i)).getPillID());
		scheduleData.setPillIds(pillIds);
	}
	
	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.save_btn) {
			if (!scheduleData.getPillIds().isEmpty()) {
				if (!idCreated) {
					Log.d("TEST", "id had not been created");
					scheduleData.setScheduleId(getNextScheduleId());
					idCreated = true;
					findViewById(R.id.delete_btn).setEnabled(true);
				}
			
				saveToDatabase();
				
				if (scheduleData.isActive()) {
					setAlarm();
					Toast.makeText(this, "Alarm is set", Toast.LENGTH_SHORT).show();
				} else
					Toast.makeText(this, "Settings saved", Toast.LENGTH_SHORT).show();
			} else
				Toast.makeText(this, "Please select pills", Toast.LENGTH_SHORT).show();
			
		} else if (v.getId() == R.id.cancel_btn) {
			finish();
		} else if (v.getId() == R.id.delete_btn) {
			PillboxDB db = new PillboxDB(this);
			db.deleteSchedule(scheduleData.getScheduleId());
			finish();
		}
			
	}
	
	private void saveToDatabase() {
		PillboxDB db = new PillboxDB(this);
		Schedule existingSchedule = 
				db.getSchedule(scheduleData.getDayOfWeek(), scheduleData.getHour(), scheduleData.getMinute());
		
		if (existingSchedule == null) {
			if (idExists) {
				db.updateSchedule(scheduleData);
			} else {
				db.insertSchedule(scheduleData);
				idExists = true;
			}
		} else {
			db.updateSchedule(scheduleData);
		}
	}
	
	private int getNextScheduleId() {
		SharedPreferences sharedPref = getSharedPreferences(
				getString(R.string.alarm_id_count_key), Context.MODE_PRIVATE);

		int newId = sharedPref.getInt("alarmIdCount", 1);
		
		SharedPreferences.Editor editor = sharedPref.edit();
		editor.putInt("alarmIdCount", newId + 1);
		editor.commit();
		
		return newId;
	}
	
	private void setAlarm() {
		Calendar calendar = Calendar.getInstance();
		calendar.set(Calendar.HOUR_OF_DAY, scheduleData.getHour());
		calendar.set(Calendar.MINUTE, scheduleData.getMinute());
		calendar.set(Calendar.SECOND, 0);
		
		AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
		
		Intent intent = new Intent("pillbox.action.FIRE_ALARM");
		intent.putExtra("alarmBy", scheduleData.getAlarmBy());
		intent.putExtra("scheduleId", scheduleData.getScheduleId());
		/*String[] pillNames = new String[scheduleData.getPillIds().size()];
		for (int i = 0; i < pillNames.length; i++)
			pillNames[i] = allPills.get(i).getName();
		intent.putExtra("pillNames", pillNames);
		*/
		intent.putExtra("pillIds", scheduleData.getPillIds());
		
		PendingIntent pendingIntent;
		long alarmTime;
		int scheduleId = scheduleData.getScheduleId();
		
		calendar.set(Calendar.DAY_OF_WEEK, scheduleData.getDayOfWeek());
		alarmTime = computeAlarmTime(calendar.getTimeInMillis());
		
		pendingIntent = PendingIntent.getBroadcast(this, scheduleId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
		alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, alarmTime, AlarmManager.INTERVAL_DAY * 7, pendingIntent);

	}
	
	private long computeAlarmTime(long time) {
		// if the alarm time is already passed, set it for next week
		long alarmTime = time;
		if (isPastCurrentTime(time))
			alarmTime += AlarmManager.INTERVAL_DAY * 7;
		return alarmTime;
	}
	
	private boolean isPastCurrentTime(long time) {
		if (time < System.currentTimeMillis())
			return true;
		return false;
	}
	
}